package com.ruoyi.network.common;

import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Date;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;


public class NioSocket {
	private SocketChannel socketChannel;
	private volatile boolean isBind = false;
	private Selector selector;
	private Date createTime = new Date();
	private String name;
	private SelectionKey selectionKey;
	public BlockingQueue<ByteBuffer> queue = new LinkedBlockingDeque<>();

	public NioSocket(String name, Selector selector, SocketChannel socketChannel, boolean isBind) throws Exception {
		this.name = name;
		this.selector = selector;
		this.socketChannel = socketChannel;
		this.isBind = isBind;

		// 禁用Nagle算法。Nagle算法是一种减少小包发送次数的技术，但它可能会导致延迟。通过设置TCP_NODELAY选项，你可以禁用Nagle算法，以减少数据传输的延迟。这可以通过调用
		// socketChannel.setOption(StandardSocketOptions.TCP_NODELAY, true);
		// 设置发送缓冲区大小
		socketChannel.setOption(StandardSocketOptions.SO_SNDBUF, Constant.SO_SNDBUF_SIZE);
		// 设置接收缓冲区大小(TCP协议滑动窗口)
		// 虽然这不会直接影响对端的接收缓冲区，但增加客户端的发送缓冲区大小可以允许更多的数据在本地缓存，从而可能减少因网络拥塞导致的写操作阻塞
		socketChannel.setOption(StandardSocketOptions.SO_RCVBUF, Constant.SO_RCVBUF_SIZE);
		// 这个选项被启用时，它会在TCP连接空闲时自动发送探测包，以确保连接仍然有效。这通常用于检测"死"连接，即那些由于某种原因（如对方主机崩溃或网络中断）而不再可用的连接
		// 具体来说，当SO_KEEPALIVE选项被设置后，如果在一段时间内（通常是2小时，但这个值可能因操作系统而异）在TCP连接上没有数据交换，操作系统会自动发送一个"保持存活"（keepalive）探测包给对方。对方必须响应这个探测包。根据对方的响应，操作系统会采取适当的行动，如关闭连接或继续等待
		socketChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
		// 当您调用close()方法时，底层TCP连接会尝试在1秒内发送和确认剩余的数据。如果在这段时间内所有数据都被成功处理，那么连接会正常关闭。否则，连接会被强制关闭
		// socketChannel.setOption(StandardSocketOptions.SO_LINGER, 1); // 设置linger时间为1秒

	}
	
	public BlockingQueue<ByteBuffer> getQueue() {
		return queue;
	}
	
	public SelectionKey getSelectionKey() {
		return selectionKey;
	}
	
	public void setSelectionKey(SelectionKey selectionKey) {
		this.selectionKey = selectionKey;
	}

	public Selector getSelector() {
		return selector;
	}

	public SocketChannel getSocketChannel() {
		return socketChannel;
	}

	public void setSocketChannel(SocketChannel socketChannel) {
		this.socketChannel = socketChannel;
	}

	public boolean isBind() {
		return isBind;
	}

	public void setBind(boolean isBind) {
		this.isBind = isBind;
	}

	public Date getCreateTime() {
		return createTime;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

}
